home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -serious- / workbench / directoryopus4 / dopus4_src / library / listview.c < prev    next >
C/C++ Source or Header  |  2000-03-11  |  26KB  |  806 lines

  1. /*
  2.  
  3. Directory Opus 4
  4. Original GPL release version 4.12
  5. Copyright 1993-2000 Jonathan Potter
  6.  
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20.  
  21. All users of Directory Opus 4 (including versions distributed
  22. under the GPL) are entitled to upgrade to the latest version of
  23. Directory Opus version 5 at a reduced price. Please see
  24. http://www.gpsoft.com.au for more information.
  25.  
  26. The release of Directory Opus 4 under the GPL in NO WAY affects
  27. the existing commercial status of Directory Opus 5.
  28.  
  29. */
  30.  
  31. #include "dopuslib.h"
  32.  
  33. #define LIST_IDBASE 32767
  34.  
  35. #define GAD_SLIDER 0
  36. #define GAD_UP     1
  37. #define GAD_DOWN   2
  38.  
  39. extern char nullstring[];
  40. //int _FPERR,_SIGFPE;
  41.  
  42. void DisplayView(struct DOpusListView *);
  43. void dohilite(struct DOpusListView *,int);
  44. void savepens(struct DOpusListView *);
  45. void restorepens(struct DOpusListView *);
  46. int scroll_view(struct DOpusListView *,int,int *,int);
  47. int view_valid(struct DOpusListView *,int);
  48.  
  49. char nullstring[]="                                                                                                                                ";
  50.  
  51. __saveds DoAddListView(register struct DOpusListView *view __asm("a0"),
  52.   register int count __asm("d0"))
  53. {
  54.   struct RastPort *rp;
  55.   int a,addcount=0;
  56.  
  57.   while (view && (addcount<count)) {
  58.     view->key=NULL; view->selected=NULL;
  59.     view->gadadd=0; view->chk=view->itemselected;
  60.     if (view->items)
  61.       for (view->count=0;view->items[view->count] &&
  62.         (!(view->flags&DLVF_ENDNL) || view->items[view->count][0]);view->count++);
  63.     else view->count=0;
  64.  
  65.     if (!(view->listgads=(struct Gadget *)DoAllocRemember(&view->key,sizeof(struct Gadget)*3,MEMF_CLEAR)) ||
  66.       !(view->listimage=(struct Image *)DoAllocRemember(&view->key,sizeof(struct Image),MEMF_CLEAR)) ||
  67.       !(view->listprop=(struct PropInfo *)DoAllocRemember(&view->key,sizeof(struct PropInfo),MEMF_CLEAR)) ||
  68.       !(view->selected=(char *)DoAllocRemember(&view->key,view->count,MEMF_CLEAR))) {
  69.       DoFreeRemember(&view->key);
  70.       break;
  71.     }
  72.     if (view->selectarray) CopyMem(view->selectarray,view->selected,view->count);
  73.     if (view->slidercol==-1) view->slidercol=1;
  74.     if (view->sliderbgcol==-1) view->slidercol=0;
  75.     if (view->textcol==-1) view->textcol=1;
  76.     if (view->boxhi==-1) view->boxhi=1;
  77.     if (view->boxlo==-1) view->boxlo=2;
  78.     if (view->arrowfg==-1) view->arrowfg=1;
  79.     if (view->arrowbg==-1) view->arrowbg=0;
  80.     if (view->itemfg==-1) view->itemfg=1;
  81.     if (view->itembg==-1) view->itembg=0;
  82.     rp=view->window->RPort;
  83.     view->fw=rp->Font->tf_XSize;
  84.     view->fh=rp->Font->tf_YSize;
  85.     if (view->fh<8) view->fh=8;
  86.     view->fb=rp->Font->tf_Baseline;
  87.     view->ty=(view->fh-8)/2;
  88.     view->lines=view->h/view->fh;
  89.     view->columns=view->w/view->fw;
  90.     if (view->columns>128) view->columns=128;
  91.     view->yo=view->y+((view->h-(view->lines*view->fh))/2);
  92.     view->xo=view->x+((view->w-(view->columns*view->fw))/2);
  93.     if (view->flags&DLVF_CHECK) {
  94.       view->xo+=22;
  95.       view->columns=(view->w-22)/view->fw;
  96.     }
  97.     if (view->topitem>(view->count-view->lines)) view->topitem=view->count-view->lines;
  98.     if (view->topitem<0) view->topitem=0;
  99.  
  100.     savepens(view);
  101.     SetDrMd(rp,JAM2);
  102.     if (view->flags&DLVF_DUMB)
  103.       Do3DBox(rp,view->x,view->y,view->w,view->h,view->boxlo,view->boxhi);
  104.     else Do3DBox(rp,view->x,view->y,view->w,view->h,view->boxhi,view->boxlo);
  105.     Do3DBox(rp,view->x+view->w+4,view->y,view->sliderwidth+4,view->h-16,view->boxhi,view->boxlo);
  106.     DoArrow(rp,view->x+view->w+4,view->y+view->h-14,view->sliderwidth+4,6,view->arrowfg,view->arrowbg,0);
  107.     Do3DBox(rp,view->x+view->w+4,view->y+view->h-14,view->sliderwidth+4,6,view->boxhi,view->boxlo);
  108.     DoArrow(rp,view->x+view->w+4,view->y+view->h-6,view->sliderwidth+4,6,view->arrowfg,view->arrowbg,1);
  109.     Do3DBox(rp,view->x+view->w+4,view->y+view->h-6,view->sliderwidth+4,6,view->boxhi,view->boxlo);
  110.     if (view->title) {
  111.       SetAPen(rp,view->textcol);
  112.       a=strlen(view->title);
  113.       if (view->flags&DLVF_TTOP) Move(rp,view->x,(view->y-view->fh-2)+view->fb);
  114.       else Move(rp,view->x-6-(a*view->fw),view->yo+view->fb);
  115.       Text(rp,view->title,a);
  116.     }
  117.     view->listimage->Width=view->sliderwidth; view->listimage->Height=view->h-18;
  118.     view->listimage->Depth=1; view->listimage->PlaneOnOff=view->slidercol;
  119.     view->listprop->Flags=FREEVERT|PROPBORDERLESS;
  120.     view->listprop->VertBody=0xffff;
  121.     view->listgads[0].NextGadget=&view->listgads[1];
  122.     view->listgads[0].LeftEdge=view->x+view->w+6;
  123.     view->listgads[0].TopEdge=view->y+1;
  124.     view->listgads[0].Width=view->sliderwidth;
  125.     view->listgads[0].Height=view->h-18;
  126.     view->listgads[0].Flags=GADGHNONE;
  127.     view->listgads[0].Activation=GADGIMMEDIATE|RELVERIFY|FOLLOWMOUSE;
  128.     view->listgads[0].GadgetType=PROPGADGET;
  129.     view->listgads[0].GadgetRender=(APTR)view->listimage;
  130.     view->listgads[0].MutualExclude=view->sliderbgcol;
  131.     view->listgads[0].SpecialInfo=(APTR)view->listprop;
  132.     view->listgads[0].GadgetID=LIST_IDBASE+(view->listid*3);
  133.     view->listgads[1].LeftEdge=view->x+view->w+2;
  134.     view->listgads[1].TopEdge=view->y+view->h-15;
  135.     view->listgads[1].Width=view->sliderwidth+8;
  136.     view->listgads[1].Height=8;
  137.     view->listgads[1].Flags=GADGHCOMP;
  138.     view->listgads[1].Activation=GADGIMMEDIATE|RELVERIFY;
  139.     view->listgads[1].GadgetType=BOOLGADGET;
  140.     view->listgads[1].GadgetID=LIST_IDBASE+(view->listid*3)+1;
  141.     CopyMem((char *)&view->listgads[1],(char *)&view->listgads[2],sizeof(struct Gadget));
  142.     view->listgads[1].NextGadget=&view->listgads[2];
  143.     view->listgads[2].TopEdge+=8;
  144.     view->listgads[2].GadgetID++;
  145.     if (view->flags&DLVF_HIREC)
  146.       DoAddGadgetBorders(&view->key,&view->listgads[1],2,view->boxhi,view->boxlo);
  147.     AddGList(view->window,view->listgads,-1,3,NULL);
  148.     view->gadadd=3;
  149.     view->mx=view->xo+(view->columns*view->fw)-1;
  150.     view->my=view->yo+(view->lines*view->fh)-1;
  151.     view->oldoffset=-1;
  152.     restorepens(view);
  153.     DoFixSliderBody(view->window,&view->listgads[0],view->count,view->lines,0);
  154.     DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,2);
  155.     DisplayView(view);
  156.     view=view->next;
  157.     ++addcount;
  158.   }
  159.   return(addcount);
  160. }
  161.  
  162. void __stdargs __saveds DoFixSliderBody(struct Window *win,
  163.   struct Gadget *gad,
  164.   int count,
  165.   int lines,
  166.   int show)
  167. {
  168.   USHORT body,gh,ih,min;
  169.   struct Image *image;
  170.   struct PropInfo *pinfo;
  171.   float div;
  172.   int vh,oh;
  173.  
  174.   pinfo=(struct PropInfo *)gad->SpecialInfo;
  175.   if (pinfo->Flags&FREEVERT) {
  176.     vh=0;
  177.     gh=gad->Height;
  178.     min=KNOBVMIN;
  179.   }
  180.   else {
  181.     vh=1;
  182.     gh=gad->Width;
  183.     min=KNOBHMIN;
  184.   }
  185.   if (count<=lines) body=0xffff;
  186.   else {
  187.     body=((float)0x7fff)/(((float)count)/((float)lines));
  188.     body<<=1;
  189.   }
  190.   image=(struct Image *)gad->GadgetRender;
  191.   if (body==0) ih=min;
  192.   else {
  193.     div=(float)0xffff/(float)body;
  194.     if (div==0) div=1;
  195.     ih=(int)((float)((float)gh/div));
  196.     if (ih<min) ih=min;
  197.   }
  198.   if (vh) pinfo->HorizBody=body;
  199.   else pinfo->VertBody=body;
  200.   if (pinfo->Flags&AUTOKNOB) {
  201.     if (show && win)
  202.       NewModifyProp(gad,win,NULL,pinfo->Flags,pinfo->HorizPot,pinfo->VertPot,
  203.         pinfo->HorizBody,pinfo->VertBody,1);
  204.   }
  205.   else {
  206.     if (vh) {
  207.       oh=image->Width; image->Width=ih;
  208.     }
  209.     else {
  210.       oh=image->Height; image->Height=ih;
  211.     }
  212.     if (show && win && (oh!=ih || show==2)) DoShowSlider(win,gad);
  213.   }
  214. }
  215.  
  216. void __stdargs __saveds DoFixSliderPot(struct Window *win,
  217.   struct Gadget *gad,
  218.   int off,
  219.   int count,
  220.   int lines,
  221.   int show)
  222. {
  223.   USHORT vert,vh,gh,ih,te,oh;
  224.   float div;
  225.   struct Image *image;
  226.   struct PropInfo *pinfo;
  227.  
  228.   image=(struct Image *)gad->GadgetRender;
  229.   pinfo=(struct PropInfo *)gad->SpecialInfo;
  230.   if (pinfo->Flags&FREEVERT) {
  231.     vh=0;
  232.     gh=gad->Height; ih=image->Height;
  233.   }
  234.   else {
  235.     vh=1;
  236.     gh=gad->Width; ih=image->Width;
  237.   }
  238.  
  239.   if (count<=lines) vert=0;
  240.   else vert=(off*0xffff)/(count-lines);
  241.   if (vert==0) te=0;
  242.   else {
  243.     div=(float)0xffff/(float)vert;
  244.     if (div==0) div=1;
  245.     te=(int)((float)((float)(gh-ih)/div));
  246.   }
  247.   if (vh) pinfo->HorizPot=vert;
  248.   else pinfo->VertPot=vert;
  249.   if (pinfo->Flags&AUTOKNOB) {
  250.     if (show && win)
  251.       NewModifyProp(gad,win,NULL,pinfo->Flags,pinfo->HorizPot,pinfo->VertPot,
  252.         pinfo->HorizBody,pinfo->VertBody,1);
  253.   }
  254.   else {
  255.     if (vh) {
  256.       oh=image->LeftEdge; image->LeftEdge=te;
  257.     }
  258.     else {
  259.       oh=image->TopEdge; image->TopEdge=te;
  260.     }
  261.     if (show && win && (oh!=te || show==2)) DoShowSlider(win,gad);
  262.   }
  263. }
  264.  
  265. void __saveds DoShowSlider(register struct Window *win __asm("a0"),
  266.   register struct Gadget *gad __asm("a1"))
  267. {
  268.   int ob,ot,y,old_pen,old_mode;
  269.   struct Image *image;
  270.   struct PropInfo *pinfo;
  271.   struct RastPort *r;
  272.  
  273.   pinfo=(struct PropInfo *)gad->SpecialInfo;
  274.  
  275.   if (pinfo->Flags&AUTOKNOB) {
  276.     RefreshGList(gad,win,NULL,1);
  277.     return;
  278.   }
  279.  
  280.   image=(struct Image *)gad->GadgetRender;
  281.  
  282.   r=win->RPort;
  283.   old_pen=r->FgPen;
  284.   old_mode=r->DrawMode;
  285.  
  286.   SetAPen(r,gad->MutualExclude);
  287.   SetDrMd(r,JAM1);
  288.  
  289.   if (pinfo->Flags&FREEVERT) {
  290.     ob=image->TopEdge+image->Height;
  291.     ot=image->TopEdge; y=gad->LeftEdge+gad->Width+1;
  292.     if (ot>=0) RectFill(r,gad->LeftEdge-2,gad->TopEdge-1,y,gad->TopEdge+ot-1);
  293.     if (ob<=gad->Height) RectFill(r,gad->LeftEdge-2,gad->TopEdge+ob,y,gad->TopEdge+gad->Height);
  294.     if (gad->MutualExclude) {
  295.       RectFill(r,gad->LeftEdge-2,gad->TopEdge+ot,gad->LeftEdge-1,gad->TopEdge+ob);
  296.       RectFill(r,y-1,gad->TopEdge+ot,y,gad->TopEdge+ob);
  297.     }
  298.   }
  299.   else {
  300.     ob=image->LeftEdge+image->Width;
  301.     ot=image->LeftEdge; y=gad->TopEdge+gad->Height+1;
  302.     if (ot>=0) RectFill(r,gad->LeftEdge-2,gad->TopEdge-1,gad->LeftEdge+ot-1,y-1);
  303.     if (ob<=gad->Width) RectFill(r,gad->LeftEdge+ob,gad->TopEdge-1,gad->LeftEdge+gad->Width+1,y-1);
  304.     if (gad->MutualExclude) {
  305.       RectFill(r,gad->LeftEdge+ot,gad->TopEdge-1,gad->LeftEdge+ob,gad->TopEdge-1);
  306.       RectFill(r,gad->LeftEdge+ot,y-1,gad->LeftEdge+ob,y-1);
  307.     }
  308.   }
  309.   DrawImage(r,image,gad->LeftEdge,gad->TopEdge);
  310.  
  311.   SetAPen(r,old_pen);
  312.   SetDrMd(r,old_mode);
  313. }
  314.  
  315. void DisplayView(view)
  316. struct DOpusListView *view;
  317. {
  318.   struct RastPort *rp;
  319.   int y,a,b,top,bot,dif,dir,start,end,step,w;
  320.   char buf[128];
  321.   static UWORD ditherdata[2]={0x8888,0x2222};
  322.  
  323.   savepens(view);
  324.   if (view->oldoffset==-1 || (dif=(view->oldoffset-view->topitem))>=view->lines || dif<=-view->lines) {
  325.     top=view->topitem;
  326.     bot=view->topitem+view->lines-1;
  327.     dir=0;
  328.   }
  329.   else if (dif<0) {
  330.     top=view->topitem+view->lines+dif;
  331.     bot=view->topitem+view->lines-1;
  332.     dir=view->fh;
  333.   }
  334.   else if (dif>0) {
  335.     top=view->topitem;
  336.     bot=view->topitem+dif-1;
  337.     dir=-view->fh;
  338.   }
  339.   else return;
  340.   rp=view->window->RPort;
  341.   SetAPen(rp,view->itemfg); SetBPen(rp,view->itembg);
  342.   SetDrMd(rp,JAM2);
  343.   start=view->topitem; end=view->topitem+view->lines; step=1;
  344.   if (dir>0) y=view->yo+view->fb+(view->fh*(view->lines-1));
  345.   else {
  346.     y=view->yo+view->fb;
  347.     if (dir) {
  348.       start=end-1; end=view->topitem-1; step=-1;
  349.     }
  350.   }
  351.   if (!dir && view->flags&DLVF_CHECK) ScrollRaster(rp,0,view->lines*view->fh,view->x,view->yo,view->xo-1,view->my);
  352.   w=view->w-(view->xo-view->x);
  353.   for (a=start;a!=end;a+=step) {
  354.     if (a>=top && a<=bot) {
  355.       CopyMem(nullstring,buf,view->columns);
  356.       if (view->items && a<view->count && view->items[a] &&
  357.         (!(view->flags&DLVF_ENDNL) || view->items[a][0])) {
  358.         b=strlen(view->items[a]); if (b>view->columns) b=view->columns;
  359.         CopyMem(view->items[a],buf,b);
  360.       }
  361.       Move(rp,view->xo,y);
  362.       if (dir) {
  363.         if (dir<0) ClipBlit(rp,view->xo,view->yo,rp,view->xo,view->yo+view->fh,
  364.           w,(view->lines-1)*view->fh,0xc0);
  365.         else ClipBlit(rp,view->xo,view->yo+view->fh,rp,view->xo,view->yo,
  366.           w,(view->lines-1)*view->fh,0xc0);
  367.         if (view->flags&DLVF_CHECK) ScrollRaster(rp,0,dir,view->x,view->yo,view->xo-1,view->my);
  368.       }
  369.       Text(rp,buf,view->columns);
  370.       if (view->selectarray && view->selectarray[a]&LVARRAY_DISABLED) {
  371.         rp->AreaPtrn=ditherdata; rp->AreaPtSz=1;
  372.         SetDrMd(rp,JAM1);
  373.         SetAPen(rp,view->itembg);
  374.         RectFill(rp,view->xo,y-view->fb,rp->cp_x-1,(y-view->fb)+view->fh-1);
  375.         SetAPen(rp,view->itemfg);
  376.         SetDrMd(rp,JAM2);
  377.         rp->AreaPtrn=NULL; rp->AreaPtSz=0;
  378.       }
  379.       if (a<view->count) {
  380.         if ((view->flags&DLVF_MULTI && view->selected[a]&LVARRAY_SELECTED) ||
  381.           (view->flags&DLVF_LEAVE && view->itemselected==a)) {
  382.           if (!(view->flags&DLVF_TOGGLE) || view->chk==view->itemselected) {
  383.             if (view->flags&DLVF_CHECK) DrawCheckMark(rp,view->xo-18,y+view->ty-view->fb,1);
  384.             else {
  385.               SetDrMd(rp,COMPLEMENT);
  386.               if (dir<0) b=0;
  387.               else if (dir>0) b=view->lines-1;
  388.               else b=a-view->topitem;
  389.               dohilite(view,b);
  390.               SetDrMd(rp,JAM2);
  391.             }
  392.           }
  393.         }
  394.       }
  395.     }
  396.     if (!dir) y+=view->fh;
  397.   }
  398.   view->oldoffset=view->topitem;
  399.   restorepens(view);
  400. }
  401.  
  402. __stdargs __saveds DoGetSliderPos(struct Gadget *gad,
  403.   int count,
  404.   int lines)
  405. {
  406.   int i;
  407.   USHORT vertpot;
  408.   struct PropInfo *pinfo;
  409.   float div;
  410.  
  411.   pinfo=(struct PropInfo *)gad->SpecialInfo;
  412.   if (pinfo->Flags&FREEVERT) vertpot=pinfo->VertPot;
  413.   else vertpot=pinfo->HorizPot;
  414.  
  415.   if (count<lines || vertpot==0) return(0);
  416.   div=(float)0xffff/(float)vertpot;
  417.   if (div==0) div=1;
  418.   i=(int)((float)((float)((count-lines)+1)/div));
  419.   if (i>(count-lines)) i=count-lines;
  420.   if (i<0) i=0;
  421.   return(i);
  422. }
  423.  
  424. struct DOpusListView * __saveds
  425.   DoListViewIDCMP(
  426.     register struct DOpusListView *view __asm("a0"),
  427.     register struct IntuiMessage *imsg __asm("a1"))
  428. {
  429.   int gadgetid,list,x,y,rep,xo,histate=0,offset,itemnum,newoffset,lastout=0,temp;
  430.   ULONG class,idcmpflags;
  431.   USHORT code;
  432.  
  433.   class=imsg->Class;
  434.   code=imsg->Code;
  435.   idcmpflags=view->window->IDCMPFlags;
  436.  
  437.   if (class==GADGETUP || class==GADGETDOWN) {
  438.     gadgetid=((struct Gadget *)imsg->IAddress)->GadgetID;
  439.     if (gadgetid<LIST_IDBASE) return((struct DOpusListView *)-1);
  440.     gadgetid-=LIST_IDBASE; list=gadgetid/3;
  441.     gadgetid%=3;
  442.     while (view) {
  443.       if (view->listid==list && view->window==imsg->IDCMPWindow) break;
  444.       view=view->next;
  445.     }
  446.     if (!view) return((struct DOpusListView *)-1);
  447.     ReplyMsg((struct Message *)imsg);
  448.  
  449.     if (!(idcmpflags&IDCMP_MOUSEMOVE)) ModifyIDCMP(view->window,idcmpflags|IDCMP_MOUSEMOVE);
  450.  
  451.     switch (gadgetid) {
  452.       case GAD_SLIDER:
  453.         view->topitem=DoGetSliderPos(&view->listgads[0],view->count,view->lines);
  454.         DisplayView(view);
  455.         if (view->sliderbgcol) DoShowSlider(view->window,&view->listgads[0]);
  456.         if (class==IDCMP_GADGETDOWN) {
  457.           FOREVER {
  458.             Wait(1<<view->window->UserPort->mp_SigBit);
  459.             while (imsg=(struct IntuiMessage *)GetMsg(view->window->UserPort)) {
  460.               class=imsg->Class;
  461.               ReplyMsg((struct Message *)imsg);
  462.               if (class==IDCMP_MOUSEMOVE) {
  463.                 view->topitem=DoGetSliderPos(&view->listgads[0],view->count,view->lines);
  464.                 if (view->sliderbgcol) DoShowSlider(view->window,&view->listgads[0]);
  465.                 DisplayView(view);
  466.               }
  467.               else if (class==IDCMP_GADGETUP) break;
  468.             }
  469.             if (class==IDCMP_GADGETUP) break;
  470.           }
  471.           view->topitem=DoGetSliderPos(&view->listgads[0],view->count,view->lines);
  472.           if (view->sliderbgcol) DoShowSlider(view->window,&view->listgads[0]);
  473.           DisplayView(view);
  474.         }
  475.         break;
  476.  
  477.       case GAD_UP:
  478.         if (view->topitem==0) break;
  479.         --view->topitem;
  480.       case GAD_DOWN:
  481.         if (gadgetid==GAD_DOWN) {
  482.           if (view->topitem>view->count-(view->lines+1)) break;
  483.           ++view->topitem;
  484.         }
  485.         DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,1);
  486.         DisplayView(view);
  487.         Delay(5);
  488.         FOREVER {
  489.           if (imsg=(struct IntuiMessage *)GetMsg(view->window->UserPort)) {
  490.             class=imsg->Class; code=imsg->Code;
  491.             ReplyMsg((struct Message *)imsg);
  492.             if (class==IDCMP_GADGETUP || (class==IDCMP_MOUSEBUTTONS && code==SELECTUP))
  493.               break;
  494.           }
  495.           if (gadgetid==GAD_UP) {
  496.             if (view->topitem==0) break;
  497.             --view->topitem;
  498.           }
  499.           else {
  500.             if (view->topitem>view->count-(view->lines+1)) break;
  501.             ++view->topitem;
  502.           }
  503.           DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,1);
  504.           DisplayView(view);
  505.           if (view->flags&DLVF_SLOW) Delay(1);
  506.           else WaitTOF();
  507.         }
  508.         break;
  509.     }
  510.     ModifyIDCMP(view->window,idcmpflags);
  511.     return(NULL);
  512.   }
  513.   else if (class==IDCMP_MOUSEBUTTONS && code==SELECTDOWN) {
  514.     x=imsg->MouseX;
  515.     y=imsg->MouseY;
  516.  
  517.     while (view) {
  518.       if (view->window==imsg->IDCMPWindow && !(view->flags&DLVF_DUMB)) {
  519.         if (view->flags&DLVF_CHECK) xo=view->xo-22;
  520.         else xo=view->xo;
  521.         if (x>=xo && x<view->mx && y>=view->yo && y<view->my) break;
  522.       }
  523.       view=view->next;
  524.     }
  525.     if (!view) return((struct DOpusListView *)-1);
  526.     ReplyMsg((struct Message *)imsg);
  527.  
  528.     offset=(y-view->yo)/view->fh;
  529.     itemnum=offset+view->topitem;
  530.     if (itemnum>=view->count) {
  531.       itemnum=view->count-1;
  532.       offset=itemnum-view->topitem;
  533.       if (offset<0) return(NULL);
  534.     }
  535.  
  536.     ModifyIDCMP(view->window,idcmpflags|IDCMP_MOUSEBUTTONS|IDCMP_MOUSEMOVE|IDCMP_INTUITICKS);
  537.     if (!(rep=view->window->Flags&WFLG_REPORTMOUSE))
  538.       view->window->Flags|=WFLG_REPORTMOUSE;
  539.  
  540.     savepens(view);
  541.     if (view_valid(view,itemnum)) {
  542.       dohilite(view,offset);
  543.       histate=1;
  544.     }
  545.  
  546.     FOREVER {
  547.       while (imsg=(struct IntuiMessage *)GetMsg(view->window->UserPort)) {
  548.         class=imsg->Class;
  549.         code=imsg->Code;
  550.         x=imsg->MouseX;
  551.         y=imsg->MouseY;
  552.         ReplyMsg((struct Message *)imsg);
  553.  
  554.         if (class==IDCMP_MOUSEBUTTONS) {
  555.           if (code==SELECTUP) break;
  556.           if (code==MENUUP) {
  557.             if (histate) {
  558.               histate=0;
  559.               dohilite(view,offset);
  560.             }
  561.             break;
  562.           }
  563.         }
  564.         else if (class==IDCMP_INTUITICKS) {
  565.           if ((newoffset=((y-view->yo)/view->fh))!=offset) {
  566.             newoffset=scroll_view(view,newoffset,&histate,offset);
  567.             if (newoffset>=0 && newoffset<view->lines) {
  568.               offset=newoffset;
  569.               temp=itemnum;
  570.               itemnum=view->topitem+offset;
  571.               if (itemnum!=temp && view_valid(view,itemnum)) {
  572.                 histate=1;
  573.                 dohilite(view,offset);
  574.               }
  575.             }
  576.           }
  577.         }
  578.         else if (class==IDCMP_MOUSEMOVE) {
  579.           if ((newoffset=((y-view->yo)/view->fh))!=offset || x<xo || x>=view->mx || y<view->yo) {
  580.             if (y<view->yo || y>view->yo+view->h) {
  581.               if (lastout) continue;
  582.               lastout=1;
  583.             }
  584.             else lastout=0;
  585.             if (view->count<view->lines &&
  586.               newoffset>=view->count &&
  587.               offset>=view->count-1 && histate) continue;
  588.             if (histate) {
  589.               histate=0;
  590.               dohilite(view,offset);
  591.             }
  592.             if (x<xo || x>=view->mx) continue;
  593.             newoffset=scroll_view(view,newoffset,&histate,0);
  594.             if (newoffset>=0 && newoffset<view->lines) {
  595.               offset=newoffset;
  596.               itemnum=view->topitem+offset;
  597.               if (view_valid(view,itemnum)) {
  598.                 histate=1;
  599.                 dohilite(view,offset);
  600.               }
  601.             }
  602.           }
  603.           else if (!histate) {
  604.             if (view_valid(view,itemnum)) {
  605.               histate=1;
  606.               dohilite(view,offset);
  607.             }
  608.           }
  609.         }
  610.       }
  611.       if (class==IDCMP_MOUSEBUTTONS && (code==SELECTUP || code==MENUUP)) break;
  612.       Wait(1<<view->window->UserPort->mp_SigBit);
  613.     }
  614.  
  615.     if (histate) {
  616.       if (view->flags&DLVF_MULTI) {
  617.         view->selected[itemnum]^=LVARRAY_SELECTED;
  618.         if (view->flags&DLVF_CHECK) {
  619.           dohilite(view,offset);
  620.           SetAPen(view->window->RPort,view->itemfg);
  621.           DrawCheckMark(view->window->RPort,
  622.             view->xo-18,
  623.             view->yo+(view->fh*offset)+view->ty,
  624.             (view->selected[itemnum]&LVARRAY_SELECTED));
  625.         }
  626.       }
  627.       else if (view->flags&DLVF_LEAVE) {
  628.         dohilite(view,offset);
  629.         SetAPen(view->window->RPort,view->itemfg);
  630.         if (view->itemselected==itemnum) {
  631.           if (view->flags&DLVF_TOGGLE) {
  632.             if (view->chk==view->itemselected) {
  633.               if (view->flags&DLVF_CHECK) {
  634.                 DrawCheckMark(view->window->RPort,
  635.                   view->xo-18,
  636.                   view->yo+(view->fh*offset)+view->ty,
  637.                   0);
  638.               }
  639.               else dohilite(view,offset);
  640.               view->chk=-1;
  641.             }
  642.             else {
  643.               if (view->flags&DLVF_CHECK) {
  644.                 DrawCheckMark(view->window->RPort,
  645.                   view->xo-18,
  646.                   view->yo+(view->fh*offset)+view->ty,
  647.                   1);
  648.               }
  649.               else dohilite(view,offset);
  650.               view->chk=view->itemselected;
  651.             }
  652.           }
  653.         }
  654.         else {
  655.           if (view->flags&DLVF_CHECK) {
  656.             DrawCheckMark(view->window->RPort,
  657.               view->xo-18,
  658.               view->yo+(view->fh*offset)+view->ty,
  659.               1);
  660.           }
  661.           else dohilite(view,offset);
  662.           if (view->chk>-1) {
  663.             y=view->chk-view->topitem;
  664.             if (y>=0 && y<view->lines) {
  665.               if (view->flags&DLVF_CHECK) {
  666.                 DrawCheckMark(view->window->RPort,
  667.                   view->xo-18,
  668.                   view->yo+(view->fh*y)+view->ty,
  669.                   0);
  670.               }
  671.               else dohilite(view,y);
  672.             }
  673.           }
  674.           view->chk=itemnum;
  675.         }
  676.       }
  677.       else dohilite(view,offset);
  678.     }
  679.     if (!rep) view->window->Flags&=~WFLG_REPORTMOUSE;
  680.     ModifyIDCMP(view->window,idcmpflags);
  681.     restorepens(view);
  682.     if (histate) {
  683.       view->itemselected=itemnum;
  684.       return(view);
  685.     }
  686.     return(NULL);
  687.   }
  688.   return((struct DOpusListView *)-1);
  689. }
  690.  
  691. void dohilite(view,a)
  692. struct DOpusListView *view;
  693. int a;
  694. {
  695.   int x,mode;
  696.  
  697.   mode=view->window->RPort->DrawMode;
  698.   SetDrMd(view->window->RPort,COMPLEMENT);
  699.   if (view->flags&DLVF_CHECK) x=view->xo-22;
  700.   else x=view->xo;
  701.   RectFill(view->window->RPort,x,view->yo+(view->fh*a),view->mx,view->yo+(view->fh*(a+1))-1);
  702.   SetDrMd(view->window->RPort,mode);
  703. }
  704.  
  705. void savepens(view)
  706. struct DOpusListView *view;
  707. {
  708.   view->ofg=view->window->RPort->FgPen;
  709.   view->obg=view->window->RPort->BgPen;
  710.   view->odm=view->window->RPort->DrawMode;
  711. }
  712.  
  713. void restorepens(view)
  714. struct DOpusListView *view;
  715. {
  716.   SetAPen(view->window->RPort,view->ofg);
  717.   SetBPen(view->window->RPort,view->obg);
  718.   SetDrMd(view->window->RPort,view->odm);
  719. }
  720.  
  721. __saveds DoRefreshListView(register struct DOpusListView *view __asm("a0"),
  722.   register int count __asm("d0"))
  723. {
  724.   int realcount=0;
  725.  
  726.   while (view && realcount<count) {
  727.     if (view->items)
  728.       for (view->count=0;view->items[view->count] &&
  729.         (!(view->flags&DLVF_ENDNL) || view->items[view->count][0]);view->count++);
  730.     else view->count=0;
  731.     if (view->selectarray) {
  732.       if (view->selected=(char *)DoAllocRemember(&view->key,view->count,MEMF_CLEAR))
  733.         CopyMem(view->selectarray,view->selected,view->count);
  734.     }
  735.     if (view->topitem>(view->count-view->lines)) view->topitem=view->count-view->lines;
  736.     if (view->topitem<0) view->topitem=0;
  737.     view->chk=view->itemselected;
  738.     DoFixSliderBody(view->window,&view->listgads[0],view->count,view->lines,0);
  739.     DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,2);
  740.     view->oldoffset=-1;
  741.     DisplayView(view);
  742.     view=view->next;
  743.     ++realcount;
  744.   }
  745.   return(realcount);
  746. }
  747.  
  748. __saveds DoRemoveListView(register struct DOpusListView *view __asm("a0"),
  749.   register int count __asm("d0"))
  750. {
  751.   int realcount=0;
  752.  
  753.   while (view && realcount<count) {
  754.     if (view->gadadd) RemoveGList(view->window,view->listgads,view->gadadd);
  755.     DoFreeRemember(&view->key);
  756.     view=view->next;
  757.     ++realcount;
  758.   }
  759.   return(realcount);
  760. }
  761.  
  762. scroll_view(view,offset,histate,oldoffset)
  763. struct DOpusListView *view;
  764. int offset,*histate,oldoffset;
  765. {
  766.   int draw=0;
  767.  
  768.   if (view->count<view->lines && offset>=view->count)
  769.     return(view->count-1);
  770.  
  771.   if (offset<0) {
  772.     if (view->topitem>0) {
  773.       --view->topitem;
  774.       draw=1;
  775.     }
  776.     offset=0;
  777.   }
  778.   else if (offset>=view->lines) {
  779.     if (view->topitem<=view->count-(view->lines+1)) {
  780.       ++view->topitem;
  781.       draw=1;
  782.     }
  783.     offset=view->lines-1;
  784.   }
  785.  
  786.   if (draw) {
  787.     if (*histate) {
  788.       *histate=0;
  789.       dohilite(view,oldoffset);
  790.     }
  791.     DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,1);
  792.     DisplayView(view);
  793.   }
  794.   return(offset);
  795. }
  796.  
  797. view_valid(view,itemnum)
  798. struct DOpusListView *view;
  799. int itemnum;
  800. {
  801.   if (itemnum<view->count &&
  802.     (!view->selectarray || !(view->selectarray[itemnum]&LVARRAY_DISABLED)))
  803.     return(1);
  804.   return(0);
  805. }
  806.